﻿using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
using System.Windows.Media;
using ICSharpCode.AvalonEdit;

namespace Peter.Logic.AvalonEdit
{
   /// <summary>
   /// Service used to mark all occurances of the find text.
   /// </summary>
   public class FindTextMarkerService : TextMarkerService
   {
      private string m_LastText;
      private bool m_IgnoreCase;

      /// <summary>
      /// Initializes the find text marker service.
      /// </summary>
      /// <param name="editor">The text editor to attach to.</param>
      public FindTextMarkerService (TextEditor editor)
         : base (editor)
      {
         this.m_LastText = string.Empty;
      }

      /// <summary>
      /// Marks all occurances of the find text.
      /// </summary>
      /// <param name="searchText">Text to mark.</param>
      /// <param name="ignoreCase">True to ignore case, otherwise false.</param>
      /// <returns>The number of items highlighted.</returns>
      public int MarkFindText (string searchText, bool ignoreCase)
      {
         int count = 0;
         if (searchText != this.m_LastText || ignoreCase != this.m_IgnoreCase || this.TextMarkerCount == 0)
         {
            this.RemoveAll ();
            this.m_LastText = searchText;
            this.m_IgnoreCase = ignoreCase;
            if (!string.IsNullOrEmpty (searchText))
            {
               var matches = Regex.Matches (this.Editor.Text, Regex.Escape (searchText),
                                            ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
               foreach (Match match in matches)
                  this.Create (match.Index, match.Length).BackgroundColor = Colors.Bisque;
               count = matches.Count;
               if (count > 0)
               {
                  var location = this.Editor.Document.GetLocation (matches [0].Index);
                  this.Editor.ScrollTo (location.Line, location.Column);
               }
            }
         }
         return count;
      }

      /// <summary>
      /// Updates all found occurances after the given offset.
      /// </summary>
      /// <param name="offset">Offset to update after.</param>
      public int UpdateAfterOffset (int offset)
      {
         var count = 0;
         if (!string.IsNullOrEmpty (this.m_LastText))
         {
            var line = this.Editor.Document.GetLineByOffset (offset);
            offset = line.Offset;
            var markers = new Collection <TextMarker> ();
            foreach (var textMarker in TextMarkers)
            {
               if (textMarker.StartOffset + textMarker.Length >= offset)
                  markers.Add (textMarker);
            }
            foreach (var textMarker in markers)
               this.Remove (textMarker);

            count = this.TextMarkerCount;
            var matches = Regex.Matches (this.Editor.Text.Substring (offset), Regex.Escape (this.m_LastText),
                                         this.m_IgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
            foreach (Match match in matches)
               this.Create (match.Index + offset, match.Length).BackgroundColor = Colors.Bisque;
            count += matches.Count;
         }
         return count;
      }
   }
}
